package fr.imag.ufrima.ima.project.ui.tools;

import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.log4j.Logger;

import fr.imag.ufrima.ima.project.core.Image;
import fr.imag.ufrima.ima.project.core.operations.Resize;
import fr.imag.ufrima.ima.project.ui.main.ImageProject;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import fr.imag.ufrima.ima.project.core.operations.TypeResize;

public class ResizeTool extends JPanel implements PropertyChangeListener {
	private Logger logger = Logger.getLogger(getClass().getName());
	private ImageProject imageProject;
	private JTextField txtWidth;
	private JTextField txtHeight;
	private JList lstPrefixedSize;
	private JComboBox cmbTypeResize;
	private JCheckBox chckbxLockSizes;

	/**
	 * Create the panel.
	 */
	public ResizeTool(ImageProject imageProject) {
		this.imageProject = imageProject;

		setLayout(new BorderLayout(0, 0));

		JPanel panel = new JPanel();

		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[] { 150 };
		gbl_panel.rowHeights = new int[] { 58, 16, 16, 58, 16, 16 };
		gbl_panel.columnWeights = new double[] { 1.0 };
		gbl_panel.rowWeights = new double[] { 0.0 };
		panel.setLayout(gbl_panel);

		JPanel pnlTop = new JPanel();
		GridBagLayout gbl_pnlTop = new GridBagLayout();
		gbl_pnlTop.columnWidths = new int[] { 75, 75 };
		gbl_pnlTop.rowHeights = new int[] { 16, 16 };
		gbl_pnlTop.columnWeights = new double[] { 0.3, 0.7 };
		gbl_pnlTop.rowWeights = new double[] { 0.0 };
		pnlTop.setLayout(gbl_pnlTop);

		JLabel lblWidth = new JLabel("Largeur:");
		GridBagConstraints gbc_lblWidth = new GridBagConstraints();
		gbc_lblWidth.anchor = GridBagConstraints.WEST;
		gbc_lblWidth.fill = GridBagConstraints.BOTH;
		gbc_lblWidth.insets = new Insets(0, 0, 5, 5);
		gbc_lblWidth.gridx = 0;
		gbc_lblWidth.gridy = 0;
		pnlTop.add(lblWidth, gbc_lblWidth);

		txtWidth = new JTextField();
		GridBagConstraints gbc_txtWidth = new GridBagConstraints();
		gbc_txtWidth.anchor = GridBagConstraints.EAST;
		gbc_txtWidth.fill = GridBagConstraints.BOTH;
		gbc_txtWidth.insets = new Insets(0, 0, 5, 0);
		gbc_txtWidth.gridx = 1;
		gbc_txtWidth.gridy = 0;
		txtWidth.addFocusListener(new FocusListener() {

			@Override
			public void focusLost(FocusEvent e) {
				// TODO Auto-generated method stub
				ResizeTool.this.updateHeight();
			}

			@Override
			public void focusGained(FocusEvent e) {
				// TODO Auto-generated method stub

			}
		});
		pnlTop.add(txtWidth, gbc_txtWidth);

		JLabel lblHeight = new JLabel("Hauteur:");
		GridBagConstraints gbc_lblHeight = new GridBagConstraints();
		gbc_lblHeight.anchor = GridBagConstraints.WEST;
		gbc_lblHeight.fill = GridBagConstraints.BOTH;
		gbc_lblHeight.insets = new Insets(0, 0, 0, 5);
		gbc_lblHeight.gridx = 0;
		gbc_lblHeight.gridy = 1;
		pnlTop.add(lblHeight, gbc_lblHeight);

		txtHeight = new JTextField();
		GridBagConstraints gbc_txtHeight = new GridBagConstraints();
		gbc_txtHeight.anchor = GridBagConstraints.EAST;
		gbc_txtHeight.fill = GridBagConstraints.BOTH;
		gbc_txtHeight.gridx = 1;
		gbc_txtHeight.gridy = 1;
		txtHeight.addFocusListener(new FocusListener() {

			@Override
			public void focusLost(FocusEvent e) {
				// TODO Auto-generated method stub
				ResizeTool.this.updateWidth();
			}

			@Override
			public void focusGained(FocusEvent e) {
				// TODO Auto-generated method stub

			}
		});
		pnlTop.add(txtHeight, gbc_txtHeight);

		GridBagConstraints gbc_pnlTop = new GridBagConstraints();
		gbc_pnlTop.weighty = 0.5;
		gbc_pnlTop.weightx = 0.5;
		gbc_pnlTop.fill = GridBagConstraints.HORIZONTAL;
		gbc_pnlTop.insets = new Insets(0, 5, 5, 5);
		gbc_pnlTop.gridx = 0;
		gbc_pnlTop.gridy = 0;
		panel.add(pnlTop, gbc_pnlTop);

		JLabel lblFixed = new JLabel("Fixed:");
		GridBagConstraints gbc_lblFixed = new GridBagConstraints();
		gbc_lblFixed.insets = new Insets(0, 5, 5, 5);
		gbc_lblFixed.gridy = 2;
		gbc_lblFixed.gridx = 0;
		gbc_lblFixed.fill = GridBagConstraints.BOTH;
		panel.add(lblFixed, gbc_lblFixed);

		lstPrefixedSize = new JList();
		lstPrefixedSize.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		lstPrefixedSize.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		lstPrefixedSize.setVisibleRowCount(5);
		lstPrefixedSize.setModel(new AbstractListModel() {
			String[] values = new String[] {"25%", "50%", "75%", "100%", "125%", "150%", "200%", "300%", "400%"};
			public int getSize() {
				return values.length;
			}
			public Object getElementAt(int index) {
				return values[index];
			}
		});
		lstPrefixedSize.setSelectedIndex(3);
		lstPrefixedSize.addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent e) {
				// TODO Auto-generated method stub
				if (lstPrefixedSize.getSelectedValue() != null) {
					String optionString = lstPrefixedSize.getSelectedValue().toString();
					float newSizeFactor = Float.valueOf(optionString.substring(0, optionString.length() - 1)) / 100;
					ResizeTool.this.updateSizeAccordingToOption(newSizeFactor);
				}
			}
		});
		GridBagConstraints gbc_lstPrefixedSize = new GridBagConstraints();
		gbc_lstPrefixedSize.insets = new Insets(0, 5, 5, 5);
		gbc_lstPrefixedSize.fill = GridBagConstraints.BOTH;
		gbc_lstPrefixedSize.gridy = 3;
		gbc_lstPrefixedSize.gridx = 0;
		panel.add(lstPrefixedSize, gbc_lstPrefixedSize);

		JButton btnApply = new JButton("Appliquer");
		btnApply.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				ResizeTool.this.scaleImage();
			}
		});
		
		GridBagConstraints gbc_btnApply = new GridBagConstraints();
		gbc_btnApply.insets = new Insets(5, 0, 0, 0);
		gbc_btnApply.gridy = 5;
		gbc_btnApply.gridx = 0;
		panel.add(btnApply, gbc_btnApply);

		add(panel, BorderLayout.NORTH);

		JPanel pnlBottom = new JPanel();
		GridBagLayout gbl_pnlBottom = new GridBagLayout();
		gbl_pnlBottom.columnWidths = new int[] { 75, 75 };
		gbl_pnlBottom.rowHeights = new int[] { 16 };
		gbl_pnlBottom.columnWeights = new double[] { 0.3, 0.7};
		gbl_pnlBottom.rowWeights = new double[] { 0.0};
		pnlBottom.setLayout(gbl_pnlBottom);
		
		GridBagConstraints gbc_pnlBottom = new GridBagConstraints();
		gbc_pnlBottom.weighty = 0.5;
		gbc_pnlBottom.weightx = 0.5;
		gbc_pnlBottom.fill = GridBagConstraints.HORIZONTAL;
		gbc_pnlBottom.insets = new Insets(0, 5, 5, 5);
		gbc_pnlBottom.gridx = 0;
		gbc_pnlBottom.gridy = 4;
		panel.add(pnlBottom, gbc_pnlBottom);
		
		JLabel lblType = new JLabel("Type:");
		GridBagConstraints gbc_lblType = new GridBagConstraints();
		gbc_lblType.insets = new Insets(0, 0, 5, 5);
		gbc_lblType.anchor = GridBagConstraints.WEST;
		gbc_lblType.gridx = 0;
		gbc_lblType.gridy = 0;
		pnlBottom.add(lblType, gbc_lblType);
		
		cmbTypeResize = new JComboBox();
		cmbTypeResize.setModel(new DefaultComboBoxModel(TypeResize.values()));
		cmbTypeResize.setSelectedIndex(0);
		GridBagConstraints gbc_comboBox = new GridBagConstraints();
		gbc_comboBox.fill = GridBagConstraints.HORIZONTAL;
		gbc_comboBox.anchor = GridBagConstraints.EAST;
		gbc_comboBox.insets = new Insets(0, 0, 5, 0);
		gbc_comboBox.gridx = 1;
		gbc_comboBox.gridy = 0;
		pnlBottom.add(cmbTypeResize, gbc_comboBox);		
		
		chckbxLockSizes = new JCheckBox("Lock Sizes");
		chckbxLockSizes.setSelected(true);
		GridBagConstraints gbc_chckbxLockSizes = new GridBagConstraints();
		gbc_chckbxLockSizes.insets = new Insets(0, 5, 5, 5);
		gbc_chckbxLockSizes.gridx = 0;
		gbc_chckbxLockSizes.gridy = 1;
		panel.add(chckbxLockSizes, gbc_chckbxLockSizes);
	}

	private void updateSizeAccordingToOption(float newSizeFactor) {
		logger.debug(String.format("Preparing to serve updateSizeAccordingToOption for: %f", newSizeFactor));

		Image image = this.imageProject.getCurrentImageDocument().getImage();
		float nw = image.getWidth();
		float nh = image.getHeight();

		nw *= newSizeFactor;
		nh *= newSizeFactor;

		txtWidth.setText(String.valueOf((int) nw));
		txtHeight.setText(String.valueOf((int) nh));
	}

	private void initTool() {
		txtWidth.setText("");
		txtHeight.setText("");
		lstPrefixedSize.clearSelection();
		txtWidth.requestFocusInWindow();
	}

	private void scaleImage() {
	
		Image image = this.imageProject.getCurrentImageDocument().getImage();
		int nw = Integer.valueOf(txtWidth.getText());
		int nh = Integer.valueOf(txtHeight.getText());

		Resize resize = new Resize(image);
		resize.setNewWidth(nw);
		resize.setNewHeight(nh);
		switch (cmbTypeResize.getSelectedIndex()) {
		case 0:
			resize.setTypeResize(TypeResize.CONSTANT);
			break;
		case 1:
			resize.setTypeResize(TypeResize.LINEAR);
			break;
		}

		imageProject.applyOperation(resize);
		
		lstPrefixedSize.setSelectedIndex(3);
		txtWidth.setText(String.valueOf(nw));
		txtHeight.setText(String.valueOf(nh));
	}

	private void updateHeight() {
		
		if (chckbxLockSizes.isSelected() && !txtWidth.getText().equals("")) {
			float w = Float.valueOf(txtWidth.getText());
			float mw = w / (float) imageProject.getCurrentImageDocument().getImage().getWidth();

			float mh = mw * imageProject.getCurrentImageDocument().getImage().getHeight();
			txtHeight.setText(Integer.toString((int) mh));
		}
	}

	private void updateWidth() {
		
		if (chckbxLockSizes.isSelected() && !txtHeight.getText().equals("")) {	
			float h = Float.valueOf(txtHeight.getText());
			float mh = h / (float) imageProject.getCurrentImageDocument().getImage().getHeight();

			float mw = mh * imageProject.getCurrentImageDocument().getImage().getWidth();
			txtWidth.setText(Integer.toString((int) mw));
		}
	}

	@Override
	public void propertyChange(PropertyChangeEvent e) {
		// TODO Auto-generated method stub
		String propertyName = e.getPropertyName();
		if ("visible".equals(propertyName)) {
			if ("true".equals(e.getNewValue().toString())) {
				logger.debug(String.format("ResizeTool has become visible.", propertyName));
				initTool();
			}
		}
	}

	public PropertyChangeListener getPropertyChangeListener() {
		return this;
	}

}
